package com.xuanwu.ai.flow.service;

import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xuanwu.ai.core.utils.IdWorker;
import com.xuanwu.ai.flow._enum.DeployTypeEnum;
import com.xuanwu.ai.flow._enum.ErrorCodeEnum;
import com.xuanwu.ai.flow.dto.FlowReqDTO;
import com.xuanwu.ai.flow.mapper.FlowChainVersionMapper;
import com.xuanwu.ai.flow.mapper.FlowManageMapper;
import com.xuanwu.ai.flow.model.FlowChain;
import com.xuanwu.ai.flow.model.FlowChainVersion;
import com.xuanwu.ai.jdbc.mybatis.LambdaExcludeEmptyQueryWrapper;
import com.xuanwu.ai.jdbc.page.Pagination;
import com.xuanwu.ai.web.exception.BizException;
import com.yomahub.liteflow.enums.FlowParserTypeEnum;
import com.yomahub.liteflow.flow.FlowBus;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class FlowManageServiceImpl {

    @Autowired
    private FlowManageMapper flowManageMapper;

    @Autowired
    private FlowChainVersionMapper flowChainVersionMapper;

    @Autowired
    private IdWorker idWorker;

    @Value("${flow.config.ip}")
    private String flowIp;

    @Value("${flow.config.port}")
    private String port;

    private static final String CHAIN_XML_PATTERN = "<chain name=\"{}\">{}</chain>";

    private static final String XML_PATTERN = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><flow>{}{}</flow>";


    /**
     * 获取流程列表
     *
     * @param flowReqDTO
     * @param pagination
     * @return
     */
    public PageInfo<FlowChain> getFlowList(FlowReqDTO flowReqDTO, Pagination pagination) {

        PageHelper.startPage(pagination);
        List<FlowChain> flowChainList = flowManageMapper.getFlowList(flowReqDTO);

        return PageInfo.of(flowChainList);

    }


    /**
     * 获取流程详情
     *
     * @param flowId
     * @return
     */
    public FlowChain getFlowDetail(Long flowId) {

        return flowManageMapper.selectById(flowId);

    }


    /**
     * 保存流程信息
     *
     * @param flowChain
     */
    public void saveFlow(FlowChain flowChain) {

        FlowChain exitFlowChain = flowManageMapper.selectOne(new LambdaExcludeEmptyQueryWrapper<FlowChain>().eq(FlowChain::getChainName, flowChain.getChainName()));

        if (ObjectUtils.isNotEmpty(exitFlowChain)) {
            throw new BizException(ErrorCodeEnum.FLOW_COMPLETE);
        }

        flowChain.setApplicationName("AI-Flow");
        flowChain.setId(idWorker.genId());
        flowChain.setCreateTime(new Date());
        flowChain.setStatus(DeployTypeEnum.UNDEPLOY.getDeployStatus());

        flowManageMapper.insert(flowChain);
    }


    /**
     * 更新流程信息
     *
     * @param flowChain
     */
    public void updateFlow(FlowChain flowChain) {

        FlowChain exitFlowChain = flowManageMapper.selectOne(new LambdaExcludeEmptyQueryWrapper<FlowChain>()
                .eq(FlowChain::getChainName, flowChain.getChainName())
                .ne(FlowChain::getId, flowChain.getId()));

        if (ObjectUtils.isNotEmpty(exitFlowChain)) {
            throw new BizException(ErrorCodeEnum.FLOW_COMPLETE);
        }

        // 更改流程之后，已修改待发布
        flowChain.setStatus(DeployTypeEnum.EDIT_UNDEPLOY.getDeployStatus());
        flowChain.setUpdateTime(new Date());

        flowManageMapper.updateById(flowChain);
    }


    /**
     * 发布流程信息
     *
     * @param flowId
     */
    @Transactional
    public void deployFlow(Long flowId) {

        FlowChain flowChain = flowManageMapper.selectById(flowId);

        // 流程重复发布
        if (flowChain.getStatus().equals(1)) {
            throw new BizException(ErrorCodeEnum.FLOW_REPEAT_DEPLOY);
        }

        String chainsContent = StrUtil.format(CHAIN_XML_PATTERN, flowChain.getChainName(), flowChain.getElData());

        String newContent = StrUtil.format(XML_PATTERN, "", chainsContent);

        try {
            FlowBus.refreshFlowMetaData(FlowParserTypeEnum.TYPE_EL_XML, newContent);

            // 流程发布刷新成功，生成流程版本
            FlowChainVersion flowChainVersion = new FlowChainVersion();
            BeanUtils.copyProperties(flowChain, flowChainVersion);
            flowChainVersion.setId(idWorker.genId());
            flowChainVersion.setCreateTime(new Date());
            flowChainVersion.setUpdateTime(new Date());

            flowChainVersionMapper.insert(flowChainVersion);

            // 发布成功状态
            flowChain.setStatus(DeployTypeEnum.DEPLOY_SUCCESS.getDeployStatus());
            String flowUrl = flowIp.concat(":").concat(port).concat("/api/flow/ai/").concat(String.valueOf(flowId));
            flowChain.setUrl(flowUrl);
            flowChain.setFlowVersionId(flowChainVersion.getId());

        } catch (Exception e) {
            log.error("加载流程配置失败:{}", e.getMessage());
            // 发布失败状态
            flowChain.setStatus(DeployTypeEnum.DEPLOY_FAIL.getDeployStatus());
            throw new BizException(ErrorCodeEnum.FLOW_RELOAD_FAIL);
        } finally {
            flowManageMapper.updateById(flowChain);
        }
    }

}
